import { IAssetMeta } from '../../@types/packages/asset-db/@types/public';
import { FrameworkConfig } from './framework-config';

import fs from 'fs';
import path from 'path';
import crypto from 'crypto';
import { exec } from 'child_process';

/**
 * 扩展路径
 */
export const EXTENSION_PATH = path.join(__dirname, '..', '..');

/**
 * 执行命令
 * @param command
 * @param cwd
 */
export function exeCommand(command: string, cwd: string) {
    return new Promise<{ error?: any; stdout?: string; stderr?: string }>((resolve) => {
        exec(command, { cwd: cwd }, (error, stdout, stderr) => {
            resolve({
                error: error,
                stdout: stdout,
                stderr: stderr
            });
        });
    });
}

/**
 * 资源库函数
 */
export class AssetDB {
    /**
     * 创建资源
     * @param source
     * @param target
     * @param option
     */
    static createAsset(target: string, content: string, option: { overwrite?: boolean; rename?: boolean } = {}) {
        return Editor.Message.send('asset-db', 'create-asset', target, content, option);
    }

    /** create-asset
     * 导入资源
     * @param source
     * @param target
     * @param option
     */
    static importAsset(source: string, target: string, option: { overwrite?: boolean; rename?: boolean } = {}) {
        return Editor.Message.send('asset-db', 'import-asset', source, target, option);
    }

    /**
     * 删除资源
     * @param target
     */
    static deleteAsset(target: string) {
        return Editor.Message.send('asset-db', 'delete-asset', target);
    }

    /**
     * 刷新资源
     * @param target
     */
    static refreshAsset(target: string) {
        return Editor.Message.send('asset-db', 'refresh-asset', target);
    }

    /**
     * 刷新资源
     * @param urlOrUUID
     */
    static async queryAssetMeta(urlOrUUID: string) {
        return (await Editor.Message.request('asset-db', 'query-asset-meta', urlOrUUID)) as IAssetMeta;
    }
}

/**
 * 查找文件类型
 */
export enum FindFileType {
    FILE = 1,
    DIRECTORY = 2
}

/**
 * 在指定目录中查找文件
 * @param dir
 * @param filename
 */
export function findFile(dir: string, filename: string, types: number = FindFileType.FILE | FindFileType.DIRECTORY) {
    for (let file of fs.readdirSync(dir)) {
        let npath = path.join(dir, file);
        let info = fs.statSync(npath);
        if (file === filename && (info.isDirectory() ? types & FindFileType.DIRECTORY : types & FindFileType.FILE)) {
            return npath;
        } else if (info.isDirectory()) {
            let result = findFile(npath, filename, types);
            if (result) {
                return result;
            }
        }
    }
}

/**
 * 遍历目录路径
 */
export function mapDirectory(path_: string, callback: (path: string, file: string, isdir: boolean) => boolean) {
    for (let file of fs.readdirSync(path_)) {
        let npath = path.join(path_, file);
        let info = fs.statSync(npath);
        if (callback(npath, file, info.isDirectory())) {
            return true;
        } else if (info.isDirectory()) {
            if (mapDirectory(npath, callback)) {
                return true;
            }
        }
    }
}

/**
 * 复制文件
 * @param srcPath
 * @param destPath
 */
export function copyFile(srcPath: string, destPath: string) {
    fs.writeFileSync(destPath, fs.readFileSync(srcPath));
}

/**
 * 复制目录
 * @param src
 * @param dest
 */
export function copyDirectory(srcPath: string, destPath: string) {
    if (fs.existsSync(srcPath)) {
        if (!fs.existsSync(destPath)) {
            fs.mkdirSync(destPath, { recursive: true });
        }
        for (let file of fs.readdirSync(srcPath)) {
            let spath = path.join(srcPath, file);
            let dpath = path.join(destPath, file);
            let info = fs.statSync(spath);
            if (info.isDirectory()) {
                copyDirectory(spath, dpath);
            } else {
                copyFile(spath, dpath);
            }
        }
    }
}

/**
 * 读取json文件
 *
 * @param file 文件路径
 */
export function readJsonFile(file: string) {
    if (fs.existsSync(file)) {
        return JSON.parse(fs.readFileSync(file, 'utf-8'));
    }
}

/**
 * 写入json文件
 * @param file 文件路径
 * @param json 对象
 */
export function writeJsonFile(file: string, json: any, ident = 0) {
    if (json) {
        fs.writeFileSync(file, JSON.stringify(json, null, ident));
    }
}

/**
 * 获得文件的MD5值
 * @param file
 */
export function getFileMd5(file: string) {
    return crypto.createHash('md5').update(fs.readFileSync(file)).digest('hex');
}

/**
 * 获得框架配置
 */
const modulesFile = path.join(EXTENSION_PATH, 'framework', 'config.json');
let frameworkConfig: FrameworkConfig = null;
export function getFrameworkConfig() {
    if (!frameworkConfig) {
        if (fs.existsSync(modulesFile)) {
            frameworkConfig = JSON.parse(fs.readFileSync(modulesFile, { encoding: 'utf-8' }));
        }
    }
    return frameworkConfig;
}

/**
 * 获得扩展配置
 */
const packageFile = path.join(EXTENSION_PATH, 'package.json');
let extensionConfig = null;
export function getExtensionConfig() {
    if (!extensionConfig) {
        if (fs.existsSync(packageFile)) {
            extensionConfig = JSON.parse(fs.readFileSync(packageFile, { encoding: 'utf-8' }));
        }
    }
    return extensionConfig;
}

/**
 * 获得所有游戏包
 */
export function getGamePacks() {
    let packs = {};
    let _collectGamePacks;
    _collectGamePacks = (path_: string) => {
        for (let f of fs.readdirSync(path_)) {
            let fpath = path.join(path_, f);
            let fstate = fs.statSync(fpath);
            if (fstate.isDirectory()) {
                let metafile = fpath + '.meta';
                if (fs.existsSync(metafile)) {
                    let meta = JSON.parse(fs.readFileSync(metafile, { encoding: 'utf-8' }));
                    if (meta?.userData.isBundle) {
                        packs[meta.userData.bundleName || f] = path.normalize(fpath);
                        continue;
                    }
                }
                _collectGamePacks(fpath);
            }
        }
    };
    packs['main'] = path.normalize(path.join(Editor.Project.path, 'assets'));
    _collectGamePacks(path.join(Editor.Project.path, 'assets'));
    return packs;
}
